﻿using IGeekFan.AspNetCore.Knife4jUI;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace ThresholdAssistant.Swagger
{
    /// <summary>
    /// 
    /// </summary>
    public static class SwaggerExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="title"></param>
        /// <param name="version"></param>
        /// <param name="headers">头部信息</param>
        /// <returns></returns>
        public static IServiceCollection AddKnife4Gen(this IServiceCollection services, string title, string version = "1.0.0", Dictionary<string, string> headers = null)
        {
            return services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo()
                {
                    Title = title,
                    Version = version,
                    Contact = new OpenApiContact()
                    {
                        Name = "十三尺上",
                        Email = "424063139@qq.com",
                        //Url = new Uri("https://github.com/tingli1991")
                    }
                });

                var documentFileNameList = GetXmlDocumentFileNameList();
                if (documentFileNameList != null && documentFileNameList.Any())
                {
                    foreach (var documentFileName in documentFileNameList)
                    {
                        options.IncludeXmlComments(documentFileName, true);
                    }
                }

                options.CustomOperationIds(apiDesc =>
                {
                    var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                    return $"{controllerAction?.ControllerName ?? ""}-{controllerAction?.ActionName ?? ""}";
                });

                if (headers != null && headers.Any())
                {
                    foreach (var header in headers)
                    {
                        options.AddSecurityDefinition(header.Value, new OpenApiSecurityScheme()
                        {
                            Name = header.Key,//jwt默认的参数名称
                            In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                            Type = SecuritySchemeType.ApiKey,
                            Description = "可直接在下框中输入{token}(注意中括号)"
                        });
                    }
                }
                options.EnableAnnotations();//启用特性支持
            });
        }

        /// <summary>
        /// 使用SwaggerUI
        /// </summary>
        /// <param name="app"></param>
        /// <param name="routePrefix">路由规则前缀</param>
        /// <param name="url"></param>
        /// <param name="description"></param>
        public static IApplicationBuilder UseKnife4UI(this IApplicationBuilder app, string routePrefix = "", string url = "/swagger/v1/swagger.json", string description = "swagger v1")
        {
            app.UseSwagger();
            app.UseKnife4UI(options =>
            {
                options.RoutePrefix = routePrefix;
                options.SwaggerEndpoint(url, description);
            });
            return app;
        }

        /// <summary>
        /// 获取文件名称
        /// </summary>
        /// <returns></returns>
        private static List<string> GetXmlDocumentFileNameList()
        {
            var documentFileNameList = new List<string>();
            try
            {
                var libTypeList = new List<string>() { "project", "package" };
                var fileNameList = DependencyContext.Default.CompileLibraries
                    .Where(lib => libTypeList.Contains(lib.Type)
                    && !lib.Name.StartsWith("Microsoft.", StringComparison.CurrentCultureIgnoreCase)
                    && !lib.Name.StartsWith("System.", StringComparison.CurrentCultureIgnoreCase)
                    && !lib.Name.StartsWith("runtime.", StringComparison.CurrentCultureIgnoreCase))
                    .Select(lib => $"{lib.Name}.xml").ToList();

                foreach (var fileName in fileNameList)
                {
                    string documentFileName = Path.Combine(AppContext.BaseDirectory, fileName);
                    if (File.Exists(documentFileName))
                    {
                        documentFileNameList.Add(documentFileName);
                    }
                }
            }
            catch (Exception)
            {
            }
            return documentFileNameList;
        }
    }
}